require 'nokogiri'
require 'open-uri'


class HotPost < ActiveRecord::Base

  belongs_to :user
  belongs_to :hot_post_type, :counter_cache => true
  belongs_to :the_first_sub_hot_post, :foreign_key => :the_first_sub_hot_post_id, :class_name => 'SubHotPost'
  belongs_to :the_last_sub_hot_post, :foreign_key => :the_last_sub_hot_post_id, :class_name => 'SubHotPost'
  belongs_to :the_first_lz_sub_hot_post, :foreign_key => :the_first_lz_sub_hot_post_id, :class_name => 'SubHotPost'
  belongs_to :the_last_lz_sub_hot_post, :foreign_key => :the_last_lz_sub_hot_post_id, :class_name => 'SubHotPost'
  has_many :sub_hot_posts, :order => 'id asc'
  has_many :follow_hot_post_settings, :order => 'updated_at desc'
  
  validates_uniqueness_of :title, :scope => :first_page_url
  
  validates_presence_of :hot_post_type_id,
    :user_id,
    :author,
    :first_page_url,
    :requested_url,
    :title,
    :first_released_at
    
  def exists_by_title?
    existed_one_by_title
  end
  
  def existed_one_by_title
    HotPost.find_by_title_and_first_page_url(title,first_page_url)
  end
  
  def find_the_first_sub_hot_post
    SubHotPost.find_by_hot_post_id(
      id,
      :order => 'id asc'
    )
  end

  def find_the_last_sub_hot_post
    SubHotPost.find_by_hot_post_id(
      id,
      :order => 'id desc'
    )
  end

  def find_the_first_lz_sub_hot_post
    SubHotPost.find_by_hot_post_id_and_author(
      id,
      author,
      :order => 'id asc'
    )
  end

  def find_the_last_lz_sub_hot_post
    SubHotPost.find_by_hot_post_id_and_author(
      id,
      author,
      :order => 'id desc'
    )
  end
  
  def the_last_sub_hot_post_by_tian_ya_page_num(page_num)
    SubHotPost.find_by_hot_post_id_and_page_num(
      id,
      page_num,
      :order => 'id desc'
    )
  end
  
  def zhui!(args = { :user => User.current_user, :scope => 'lz'})
    tools_setting = UserToolSetting::ZhuiTianYa.find_or_create_by_user_id_and_tool_id(user.id, Tool.find_by_code('zhui_tian_ya').id)
    follow_setting = FollowHotPostSetting.find_or_initialize_by_user_id_and_hot_post_id user.id, id  
    #follow_setting.read_sub_hot_post ||= the_first_sub_hot_post
    follow_setting.scope = args[:scope]
    follow_setting.save!
  end
  
  def current_user_follow_setting
    FollowHotPostSetting.find_by_user_id_and_hot_post_id_and_status User.current_user.id, id, 'zhui'
  end
  
  def had_been_zhuied
    follow_hot_post_settings.each_with_object([]) do |setting,settings|
      settings << setting if setting.status.give_up?
    end
  end
  
  def be_zhuied
    follow_hot_post_settings.each_with_object([]) do |setting,settings|
      settings << setting if setting.status.zhui?
    end
  end

  def sub_hot_posts_by_page_num(page_num)
    SubHotPost.find_all_by_hot_post_id_and_page_num hot_post.id,
      page_num,
      :order => 'position asc'
  end

  def no_lz_sub_hot_posts_count
    sub_hot_posts_count - lz_sub_hot_posts_count
  end

  def debug str
    puts str
  end

  def gbk_to_utf8(gbk_string)
    Iconv.iconv("UTF-8//IGNORE","GBK//IGNORE",gbk_string).to_s
  end

  def url_to_doc(url)
    urls_to_docs([url])[0]
  end
  
  def urls_to_docs(urls)
    @url_to_docs ||= {}
    urls.in_groups_of(20, false).each_with_object([]) do |sub_urls,threads|
      threads << Thread.new(@url_to_docs,sub_urls) do |url_to_docs,sub_urls|
        sub_urls.each do |url|
          puts "#{@url_to_docs[url] ? 'cached' : 'created'} url_to_doc in 100 threads : #{url} "
          if @url_to_docs[url].nil?
            @url_to_docs[url] = Nokogiri::HTML(open(url))
            def (@url_to_docs[url]).page_url=(page_url)
              @page_url = page_url
            end
            def (@url_to_docs[url]).page_url
              @page_url
            end
            def (@url_to_docs[url]).page_num=(page_num)
              @page_num = page_num
            end
            def (@url_to_docs[url]).page_num
              @page_num
            end
            (@url_to_docs[url]).page_url = url
            debug "=========== (@url_to_docs[url]).css('div#pageDivTop > em.current') is nil? #{(@url_to_docs[url]).css('div#pageDivTop > em.current').any?}"
            debug "=========== (@url_to_docs[url]).css('form#pageForm > em.current') is nil? #{(@url_to_docs[url]).css('form#pageForm > em.current').any?}"
#            debug "=========== (@url_to_docs[url]).css('form#pageForm > em') is #{(@url_to_docs[url]).css('form#pageForm > em')}"
            current_page_em = (@url_to_docs[url]).css('div#pageDivTop > em.current').any? ? (@url_to_docs[url]).css('div#pageDivTop > em.current') : (@url_to_docs[url]).css('form#pageForm > em.current')
            debug "=========== current_page_em is #{current_page_em}"
            (@url_to_docs[url]).page_num = current_page_em ? current_page_em.text.to_i : 1
          end
        end
      end      
    end.each do |thread|
      thread.join
    end
    urls.each_with_object([]) do |url,docs|  
      docs << @url_to_docs[url]
    end
  end

  def reset_words_count!
    self.words_count = SubHotPost.sum(:words_count, :conditions => ['hot_post_id = ?', id])
    save(false)
  end

  def status
    ActiveSupport::StringInquirer.new(self[:status])
  end
  
  def actived?
    status == 'actived'
  end
  
  def hidden?
    status == 'hidden'
  end
  
  def actived!    
    self.status = 'actived'    
    save(false)
  end

  def end!
    self.status = 'end'
    save(false)
  end
  
  def hidden!    
    self.status = 'hidden'    
    save(false)
  end
  
  def requested_url_error!
    self.the_last_error = requested_url_error
    save(false)
  end
  
  def do_if_capture_per_page_sub_hot_posts_exception 
    begin
     yield
    rescue 
      self.the_last_error = "#{$!}:#{$@}"
      save false
      debug "==#{$!}==:#{$@}"
      UserMailer.deliver_capture_hot_post_error :title => title,
        :url => first_page_url,
        :error => "#{$!}:#{$@}"
    end
  end
  
  def capturing!
    if self.trying_count < 12
      self.trying_count += 1
      self.status = 'capturing'
      save(false)      
      capture!
      self.trying_count = 0
      self.status = 'actived'      
    else
      self.status = 'hidden'
    end
    save(false)
  end  
  
  def reset_stat!        
    self.words_count = SubHotPost.sum( :words_count,  :conditions => ['hot_post_id = ?', id] )
    self.lz_sub_hot_posts_count = SubHotPost.count(
      :conditions => [
        'author = ? and hot_post_id = ?' ,
        author,
        id
      ]
    )
    self.sub_hot_posts_count = SubHotPost.count(
      :conditions => [
        'hot_post_id = ?' ,
        id
      ]
    )    
    rename_title!
    self.the_first_sub_hot_post ||= find_the_first_sub_hot_post
#    self.the_last_sub_hot_post ||= find_the_last_sub_hot_post
    self.the_first_lz_sub_hot_post ||= find_the_first_lz_sub_hot_post
#    self.the_last_lz_sub_hot_post ||= find_the_last_lz_sub_hot_post
    save false
  end
  
  
  def the_fastest_setting
    only_lz = FollowHotPostSetting.find_by_hot_post_id(
      id,
      :order => 'read_lz_sub_hot_post_id desc'
    )
    all = FollowHotPostSetting.find_by_hot_post_id(
      id,
      :order => 'read_no_lz_sub_hot_post_id desc'
    )
    only_lz.try(:read_lz_sub_hot_posts_count).try(:>=,all.try(:read_no_lz_sub_hot_posts_count)) ? only_lz : all
  end
  
  def current_user_read_position
    current_user_follow_setting.present? ? (
      current_user_follow_setting.scope.lz? ? (
        FollowHotPostSetting.count(
          :conditions => [
            'scope = ? and read_lz_sub_hot_post_id >= ? and status = ? ',
            current_user_follow_setting.scope,
            current_user_follow_setting.read_lz_sub_hot_post_id || 1,
            'zhui'
          ],
          :order => 'read_lz_sub_hot_post_id desc'
        )
      ):(
        FollowHotPostSetting.count(
          :conditions => [
            'scope = ? and read_no_lz_sub_hot_post_id >= ? and status = ? ',
            current_user_follow_setting.scope,
            current_user_follow_setting.read_no_lz_sub_hot_post_id || 1,            
            'zhui'
          ],
          :order => 'read_no_lz_sub_hot_post_id desc'
        )
      )
    ) : (
      FollowHotPostSetting.count( :conditions => [
        'hot_post_id = ? and status = ?',
        id,
        'zhui'
      ]) + 1
    )    
    
  end
  
  # 抓新的
  def self.capture_new!  
=begin    
    find_all_by_status_and_sub_hot_posts_count('actived',0, :order => 'updated_at asc').in_groups_of(20, false).each_with_object([]) do |hot_posts,threads|
      threads << Thread.new(hot_posts) do |hot_posts|
        hot_posts.each do |hot_post|
          if hot_post.requested_url_error? 
            hot_post.hidden!            
          else
            hot_post.capturing!
          end
        end
      end      
    end.each do |thread|
      thread.join
    end
=end
    hot_post = find_by_status_and_sub_hot_posts_count('actived',0, :order => 'updated_at asc') 
    if hot_post.present? 
      if hot_post.requested_url_error? 
        hot_post.hidden!
      else
        hot_post.capturing!
      end
    end
  end
  
  # 抓旧的  
  def self.capture_old!          
=begin
    all(:conditions => ["status = ? and updated_at < ?",'actived', 2.hours.ago], :order => 'updated_at asc').in_groups_of(20, false).each_with_object([]) do |hot_posts,threads|
      threads << Thread.new(hot_posts) do |hot_posts|
        hot_posts.each do |hot_post|
          if hot_post.requested_url_error? 
            hot_post.hidden!            
          else
            hot_post.capturing!
          end
        end
      end      
    end.each do |thread|
      thread.join
    end    
=end  
    hot_post = first(:conditions => ["status = ? and updated_at < ?",'actived', 1.hours.ago], :order => 'updated_at asc')
    if hot_post.present?
      if hot_post.requested_url_error? 
        hot_post.requested_url_error!  
        logger.error hot_post.requested_url_error
        UserMailer.deliver_capture_hot_post_error :title => hot_post.title, 
          :url => hot_post.requested_url,
          :error => hot_post.requested_url_error          
      else
        hot_post.capturing!
      end        
    end
  end
  
  def self.capture_all!
    if all( :conditions => ['status = ? and updated_at > ?','capturing',0.5.hours.ago]).empty?
      capture_new!
      capture_old!
    end
  end
end

